本篇文章會運用上一篇提到的二種新增方法insert
、insertMany
,以及另一種新增方法Bulk
來做執行速度比較 ; 由於insertMany
在mongodb shell
執行完會直接輸出結果,所以如果有1萬筆資料他就會一直跑一直跑……跑到天荒地老,看不到我用來計算執行時間的方法,所以本測試打算用node js
來建立測試方法。
在開始測試之前,先介紹一下另一個新增方法Bulk Insert
。
Bulk Insert
方法Bulk Insert
方法 ~Bulk Insert
在2.6
版時發佈,它也是種新增方法,效能如何等等會比較,基本使用方法有分有兩Unordered Operations
和Ordered Operations
。
Ordered Operations
,mongodb在執行列表的寫入操作時,如果其中一個發生錯誤,它就會停止下來,不會在繼續執行列表內的其它寫入操作,並且前面的操作不會rollback
。
使用範例如下。
var bulk = db.collection.initializeOrderedBulkOp();
bulk.insert( { name: "mark"} );
bulk.insert( { name: "hoho"} );
bulk.execute();
Unordered Operations
,mongodb在執行列表的寫入操作時,如果其中一個發生錯誤,它不會停止下來,會繼續執行列表內的其它寫入操作,速度較快。
使用範例如下。
var bulk = db.collection.initializeUnorderedBulkOp();
bulk.insert( { name: "mark"} );
bulk.insert( { name: "hoho"} );
bulk.execute();
Ordered
與Unordered
我們在要如何選擇使用時機呢,記好只要有相關性的操作就要選擇用Ordered
,而如果像是log
之類的,流失一兩筆也是沒差,這時可以選用Unordered
。
首先我們先建立個新的資料夾,然後在裡面執行npm init
來產生package.json
檔,最後我們需要的元件為mongodb
,這是mongodb native driver
,透過npm install mongodb --save
來進行安裝。
接下來我們建立測試檔案test.js
,內容如下,並附上github連結。
下面的程式碼有個很詭異的地方,測試資料datas
產生了三次而且完全一模一樣,會這樣寫是因為如果只寫一個datas
然後給三個方法新增,會發生Duplicate ObjectId
,也就是說用同一個物件去新增,它所建立的ObjectId
會一樣,然後就會出錯,這邊可能要去查一下mongodb native driver
的原始碼才知道為啥會降。
var mongodb = require('mongodb');
var mongodbServer = new mongodb.Server('localhost', 27017, {
auto_reconnect: true,
poolSize: 10
});
var db = new mongodb.Db('test', mongodbServer);
var count = 1000000;
db.open(function() {
db.collection('user', function(err, collection) {
/*
* Insert測試
*/
var datas = [];
for (var i = 0; i < count; i++) {
datas.push({
"name": "Mark",
"age": "20",
"size": i
});
}
console.time("Insert time");
collection.insert(datas, function(err, res) {
if (res) {
console.timeEnd("Insert time");
} else {
console.log("insert error");
}
});
/*
* InsertMany測試
*/
var datas = [];
for (var i = 0; i < count ; i++) {
datas.push({
"name": "Mark",
"age": "20",
"size": i
});
}
console.time("InsertMany time");
collection.insertMany(datas, function(err, res) {
if (res) {
console.timeEnd("InsertMany time");
} else {
console.log("insert error");
}
});
/*
* Unorder Bulk Insert 測試
*/
var datas = [];
for (var i = 0; i < count ; i++) {
datas.push({
"name": "Mark",
"age": "20",
"size": i
});
}
console.time("Bulk Insert");
var bulk = collection.initializeUnorderedBulkOp();
for (var i = 0; i < count; i++) {
bulk.insert(datas[i]);
}
bulk.execute(function(err,res){
console.timeEnd("Bulk Insert");
});
/*
* Ordered Bulk Insert 測試
*/
var datas = [];
for (var i = 0; i < count ; i++) {
datas.push({
"name": "Mark",
"age": "20",
"size": i
});
}
console.time("Bulk Insert");
var bulk = collection.initializeOrderedBulkOp();
for (var i = 0; i < count; i++) {
bulk.insert(datas[i]);
}
bulk.execute(function(err,res){
console.timeEnd("Bulk Insert");
});
});
});
測試物件大小約為38Bytes
,並且從小測到大,這邊要注意一下,由於mongodb
會進行所謂的預分配,將空間換取穩定,每當你第一次建立document
,他就會切分固定大小給你,然後你就算刪除document
時空間還是會存在,所以如果你先執行一次10萬筆測試,在執行第二次十萬筆測試時,你會發現執行速度變快了,因為它不用在預分配了。
{
"name": "Mark",
"age": "20",
"size": "1"
}
執行結果如下,每筆數測試都會執行兩次,並且不同筆數測試會先將預分配空間完全清除。
從下面執行結果可以知道幾點事情。
Bulk
操作都名顯優於insert、insertMany
。insertMany
不管數量大小都優於insert
(誒!?...那要insert
做啥)。測試案例(筆數大小) | Insert | InsertMany | Ordered Bulk | Unordered Bulk |
---|---|---|---|---|
10 (380bytes) | 150ms | 146ms | 145ms | 146ms |
10 (380bytes) | 16ms | 13ms | 11ms | 13ms |
1000 (38kb) | 201ms | 178ms | 170ms | 173ms |
1000 (38kb) | 89ms | 53ms | 42ms | 49ms |
100000(3.8mb) | 4286ms | 4103ms | 2975ms | 1755ms |
100000(3.8mb) | 4417ms | 4116ms | 2961ms | 1540ms |
1 million (38mb) | 49319ms | 45908ms | 34447ms | 18856ms |
1 million (38mb) | 44116ms | 40448ms | 29219ms | 16680ms |
10 million (380mb) | ??? | ??? | ??? | ??? |
那個1千萬筆的發生了下面的事件,應該是v8記憶體限制問題……小弟再究一下看看有沒有解法……請原諒我。
P.S 後來有找到可以使用下面這句,來將node
記憶體限制增加。
node --max-old-space-size=8192 xxxx.js
測試出來的結果是,如果需要回傳值和錯誤詳細回傳資料的話,請選擇用InsertMany
,
而如果是要新增例如log
之類的可以用Unordered Bulk
,因為掉一筆也不一定會死,
但如果是掉一筆會死的請用Ordered Bulk
。
如果測試的方法或結語有問題的話,請和我說一下~感謝~,至於那個1千萬筆的我再研究……。
P.S 今日出來是Bob
。